#pragma warning(disable:4530)
#include <string>
#include "osplatform.h"
#include <string.h>

#ifdef WIN32
//#include <windows.h>
int pthread_create(pthread_t *thread,  const  pthread_attr_t
     *attr, void *(*start_routine)( void*),void *arg)
{
	uint32 id;
	*thread = CreateThread(
		(pthread_attr_t *)attr,
		0,
		(LPTHREAD_START_ROUTINE)start_routine,
		arg,
		0,
		&id);
	return *thread == NULL;
}

pthread_t pthread_self(void)
{
	return (pthread_t)GetCurrentThreadId();
}

int pthread_join(pthread_t thread, void **value_ptr)
{
	return WaitForSingleObject(thread,INFINITE);
}

void pthread_exit(void *value_ptr)
{
	if(value_ptr)
		ExitThread(*((DWORD*)(value_ptr)));
	else
		ExitThread(0);
}

int usleep(useconds_t useconds)
{
	Sleep(useconds/1000);
	return 0;
}

int gettimeofday(struct timeval *tp, void *)
{
	uint32 mseconds = GetTickCount();
	tp->tv_sec = mseconds/1000;
	tp->tv_usec = (mseconds%1000)*1000;
	return 0;
}

int pthread_detach(pthread_t thread)
{
	CloseHandle(thread);
	return 0;
}

void bzero(void *s, int n)
{
	memset(s, 0, n);
}
#endif

// 
bool SetRecvTimeout(SOCKET s, int ntime)
{
	int nret = 0;
#ifdef WIN32
	nret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&ntime, sizeof(int));
#elif defined(_LINUX_)
	struct timeval tv;
	tv.tv_sec = ntime;
	tv.tv_usec= 0;
	nret = setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
#endif
	
	return (SOCKET_ERROR != nret);
}

bool SetSendTimeout(SOCKET s, int ntime)
{
	int nret = 0;
#ifdef WIN32
	nret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&ntime, sizeof(int));

#elif defined(_LINUX_)
	struct timeval tv;
	tv.tv_sec = ntime;
	tv.tv_usec= 0;
	nret = setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
#endif
	
	return (SOCKET_ERROR != nret);
}

bool GetSendTimeout(SOCKET s, int& ntime)
{
	int nret = 0;

#ifdef WIN32
	int nlen = 0;	
	nret = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*)&ntime, &nlen);

#elif defined(_LINUX_)

	struct timeval tv;
	socklen_t nlen = 0;

	nret = getsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, &nlen);
	ntime = tv.tv_sec;

#endif
	
	return (SOCKET_ERROR != nret);
}

bool GetRecvTimeout(SOCKET s, int& ntime)
{
	int nret = 0;

#ifdef WIN32
	int nlen = 0;

	nret = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*)&ntime, &nlen);

#elif defined(_LINUX_)
	socklen_t nlen = 0;
	struct timeval tv;
	nret = getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, &nlen);
	ntime = tv.tv_sec;

#endif
	
	return (SOCKET_ERROR != nret);
}

bool NonblockMode(SOCKET s, bool bnonblock, int rcvbufsize, int sndbufsize, bool btcp)
{
	int nret = 0;
	bool bret = false;

#if defined(WIN32)
    {
		u_long nonblocking = bnonblock;
		nret = ioctlsocket(s, FIONBIO, &nonblocking);
    }

#elif defined(_LINUX_)
      nret = fcntl(s, F_SETFL, fcntl(s, F_GETFL)|O_NONBLOCK);
#endif

	bret = (0 == nret);

// 	if(bret)
	{
		struct linger lg;
		int one = 1024*64;
		
		nret = setsockopt(s, SOL_SOCKET, SO_RCVBUF, (int8 *)&rcvbufsize, sizeof(int32));

		nret = setsockopt(s, SOL_SOCKET, SO_SNDBUF, (int8 *)&sndbufsize, sizeof(int32));
		
		one = 1;
		if(btcp)
			nret = setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (int8*)&one, sizeof(int32));

		one = 1;
		nret = setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (int8*)&one, sizeof(int32));
		
		lg.l_onoff = 1;
		lg.l_linger = 0;
		nret = setsockopt(s, SOL_SOCKET, SO_LINGER, (int8 *)&lg, sizeof(lg));
	}

	return bret;
}

bool SetAddrReusable(SOCKET s, bool busable)
{
	int cflag = busable ? 1:0;
	int nret = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&cflag,sizeof(cflag));

	return (nret == 0);
}

#ifdef _LINUX_
// return : elapsed milliseconds since an arbitrary point
long GetTickCount()
{
    tms tm;
	clock_t ret = times(&tm);

	float lret = sysconf(_SC_CLK_TCK);
	float fret = 1000. * ret / lret;
	
    return (long)fret/*times(&tm)*/;
}

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData)
{
	return 0;
}

int  WSACleanup (void)
{
	return 0;
}

BOOL SetThreadPriority(
						  HANDLE hThread, // handle to the thread
						  int nPriority   // thread priority level
						)
{
	// To set the scheduling priority of the thread
	struct sched_param param;  // scheduling priority
    int policy = SCHED_RR;     // scheduling policy

	if(0 == nPriority)		// clear the priority
	{
		policy = 0;
	}

	param.sched_priority = nPriority;
	return (0 == pthread_setschedparam(hThread, policy, &param));
}

// {
// 	return strcasecmp(s1, s2);
// }

// int strnicmp(const char *s1, const char *s2, size_t n) throw()
// {
// 	return strncasecmp(s1, s2, n);
// }

int stricmp(const char *s1, const char *s2) throw()
{
	while(1)
	{
		if(*s1 == '\0' && *s2 == '\0')
			return 0;
		else if(*s1 == '\0')
			return -1;
		else if(*s2 == '\0')
			return 1;
		if(tolower(*s1) > tolower(*s2))
			return 1;
		else if(tolower(*s1) < tolower(*s2))
			return -1;
		s1++;s2++;
	}	
	return 0;
}

int strnicmp(const char *s1, const char *s2, size_t n) throw()
{	
	while(n > 0)
	{
		if(*s1 == '\0' && *s2 == '\0')
			return 0;
		else if(*s1 == '\0')
			return -1;
		else if(*s2 == '\0')
			return 1;
		if(tolower(*s1) > tolower(*s2))
			return 1;
		else if(tolower(*s1) < tolower(*s2))
			return -1;
		s1++;s2++;

		--n;
	}

	return 0;
}

#define _itoa   itoa

char* itoa(int value, char*  str, int radix)
{
    int  rem = 0;
    int  pos = 0;
    char ch  = '@';
    do
    {
        rem    = value % radix ;
        value /= radix;
        if ( 16 == radix )
        {
            if( rem >= 10 && rem <= 15 )
            {
                switch( rem )
                {
                    case 10:
                        ch = 'a';
                        break;
                    case 11:
                        ch = 'b' ;
                        break;
                    case 12:
                        ch = 'c' ;
                        break;
                    case 13:
                        ch = 'd' ;
                        break;
                    case 14:
                        ch = 'e' ;
                        break;
                    case 15:
                        ch = 'f' ;
                        break;
                }
            }
        }
        if( '@' == ch )
        {
            str[pos++] = (char) ( rem + 0x30 );
        }
        else
        {
            str[pos++] = ch ;
        }
    }while( value != 0 );
    str[pos] = '\0' ;
    return strrev(str);
}

#define __strrev strrev

char* strrev(char* szT)
{
	std::string s(szT);
    reverse(s.begin(), s.end());
    strncpy(szT, s.c_str(), s.size());
    szT[s.size()+1] = '\0';
    return szT;
}

#endif//_LINUX_
